﻿/******************************************************************************
* SunnyUI.Localization 是基于.Net框架的C# Winform国际化多语言切换解决方案
* CopyRight (C) 2012-2021 ShenYongHua(沈永华).
* QQ群：56829229 QQ：17612584 EMail：SunnyUI@QQ.Com
*
* Blog:  https://www.cnblogs.com/yhuse
* Gitee: https://gitee.com/yhuse/SunnyUI.Localization
* Nuget: https://www.nuget.org/packages/SunnyUI.Localization/
*
* SunnyUI.Localization can be used for free under the MIT license.
* If you use this code, please keep this note.
* 如果您使用此代码，请保留此说明。
******************************************************************************
* 文件名称: UFormTranslator.cs
* 文件说明: 界面翻译器
* 当前版本: V1.0
* 创建日期: 2020-01-01
*
* 2020-09-09: V1.0.2 增加文件说明
******************************************************************************/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace SunnyUI.Localization
{
    public static class FormTranslator
    {
        private static readonly Dictionary<string, LanguageItem> Infos = new();

        private static readonly Dictionary<string, Control> Controls = new();
        private static readonly Dictionary<string, Component> Components = new();
        private static readonly Dictionary<string, DataGridViewColumn> DataGridViewColumns = new();

        private static void InitDictionary(Form form)
        {
            Controls.Clear();
            Components.Clear();
            DataGridViewColumns.Clear();

            GetControls(form);
            GetContextMenuStrips(form);
        }

        public static void Translate(Form form, CultureInfo culture)
        {
            Load(form, culture);
            InitDictionary(form);

            foreach (var info in Infos.Values)
            {
                if (info.Property.Contains("."))
                {
                    string name = info.Property.Split('.')[0];
                    string property = info.Property.Split('.')[1];
                    if (Controls.ContainsKey(name))
                    {
                        Controls[name].SetValue(property, info.Value);
                    }
                    else if (Components.ContainsKey(name))
                    {
                        Components[name].SetValue(property, info.Value);
                    }
                    else if (DataGridViewColumns.ContainsKey(name))
                    {
                        DataGridViewColumns[name].SetValue(property, info.Value);
                    }
                }
                else
                {
                    form.SetValue(info.Property, info.Value);
                }
            }
        }

        private static void SetValue(this Component ctrl, string property, string value)
        {
            var propertyInfo = ctrl.GetType().GetProperty(property);
            if (propertyInfo != null)
            {
                propertyInfo.SetValue(ctrl, value, null);
            }
        }

        private static void SetValue(this DataGridViewColumn ctrl, string property, string value)
        {
            var propertyInfo = ctrl.GetType().GetProperty(property);
            if (propertyInfo != null)
            {
                propertyInfo.SetValue(ctrl, value, null);
            }
        }

        private static void SetValue(this Control ctrl, string property, string value)
        {
            var propertyInfo = ctrl.GetType().GetProperty(property);
            if (propertyInfo != null)
            {
                propertyInfo.SetValue(ctrl, value, null);
            }
        }

        private static void GetContextMenuStrips(Form form)
        {
            FieldInfo[] fields = form.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (var info in fields)
            {
                if (info.FieldType.Name.Equals("ContextMenuStrip", StringComparison.CurrentCultureIgnoreCase))
                {
                    ContextMenuStrip context = (ContextMenuStrip)info.GetValue(form);
                    if (context != null)
                    {
                        foreach (ToolStripItem item in context.Items)
                        {
                            if (item is ToolStripMenuItem)
                            {
                                GetContextMenuStrip((ToolStripMenuItem)item);
                            }
                        }
                    }
                }
                if (info.FieldType.Name.Equals("UIContextMenuStrip", StringComparison.CurrentCultureIgnoreCase))
                {
                    ContextMenuStrip context = (ContextMenuStrip)info.GetValue(form);
                    if (context != null)
                    {
                        foreach (ToolStripItem item in context.Items)
                        {
                            if (item is ToolStripMenuItem)
                            {
                                GetContextMenuStrip((ToolStripMenuItem)item);
                            }
                        }
                    }
                }
                if (info.FieldType.Name.Equals("FolderBrowserDialog", StringComparison.CurrentCultureIgnoreCase))
                {
                    FolderBrowserDialog context = (FolderBrowserDialog)info.GetValue(form);
                    Components.Add(info.Name, context);
                }

                if (info.FieldType.Name.Equals("OpenFileDialog", StringComparison.CurrentCultureIgnoreCase))
                {
                    OpenFileDialog context = (OpenFileDialog)info.GetValue(form);
                    Components.Add(info.Name, context);
                }

                if (info.FieldType.Name.Equals("SaveFileDialog", StringComparison.CurrentCultureIgnoreCase))
                {
                    SaveFileDialog context = (SaveFileDialog)info.GetValue(form);
                    Components.Add(info.Name, context);
                }
            }
        }

        private static void GetContextMenuStrip(ToolStripMenuItem item)
        {
            if (!string.IsNullOrEmpty(item.Name) && (!Components.ContainsKey(item.Name)))
            {
                Components.Add(item.Name, item);
            }

            if (item.HasDropDownItems)
            {
                foreach (ToolStripMenuItem downItem in item.DropDownItems)
                {
                    GetContextMenuStrip(downItem);
                }
            }
        }
        private static void GetToolStripItem(ToolStripItem item)
        {
            if (!string.IsNullOrEmpty(item.Name) && (!Components.ContainsKey (item.Name )))
            {
                Components.Add(item.Name, item);
            }
            if(item is ToolStripDropDownItem)
            {
                ToolStripDropDownItem itemdrop = item as ToolStripDropDownItem;
                if (itemdrop.HasDropDownItems)
                {
                    foreach (ToolStripItem downItem in itemdrop.DropDownItems)
                    {
                        GetToolStripItem(downItem);
                    }
                }
            }
            
        }
        private static void GetControls(Control parentControl)
        {
            foreach (Control ctrl in parentControl.Controls)
            {
                if (!string.IsNullOrEmpty(ctrl.Name) && (!Controls.ContainsKey(ctrl.Name)))
                {
                    Controls.Add(ctrl.Name, ctrl);
                }

                if (ctrl.Controls.Count > 0)
                {
                    GetControls(ctrl);
                }

                if (ctrl is MenuStrip strip)
                {
                    foreach (ToolStripMenuItem item in strip.Items)
                    {
                        GetContextMenuStrip(item);
                    }
                }
                else if (ctrl is ToolStrip ts)
                {
                    foreach (ToolStripItem item in ts.Items)
                    {
                        GetToolStripItem(item);
                    }
                }
                else if (ctrl is DataGridView view)
                {
                    foreach (DataGridViewColumn column in view.Columns)
                    {
                        DataGridViewColumns.Add(column.Name, column);
                    }
                }
               
            }
        }

        private static void Load(Form form, CultureInfo culture)
        {
            Infos.Clear();
            string file = culture.LanguageFile();
            if (File.Exists(file))
            {
                IniFile ini = new IniFile(file);
                var keys = ini.GetKeys(form.Name);
                foreach (var key in keys)
                {
                    LanguageItem item = new LanguageItem { Class = form.Name, Property = key };
                    item.Value = ini.Read(item.Class, item.Property, "");
                    Infos.Add(item.Property, item);
                }
            }
        }
    }
}
